#include "keyboard.hpp"
#include "commtick.hpp"

using namespace device;
using namespace ui;

key* key::mKey[KEYBOARD_MAX_SUPPORT] = {0};
bool key::mKeyboardInit = false;
key::KeyEventDelegate key::KeyEventCallBack = 0;

bool key::StatusTimerTick(void)
{
	uint32_t i;
	uint8_t j;
	key *ptr;
	
	for(i = 0; i < KEYBOARD_MAX_SUPPORT; i++)
	{
		ptr = mKey[i];
		if(ptr == 0)
		{
			continue;
		}
		j = gpio::Read(ptr->mGpioPin.GpioPort, ptr->mGpioPin.GpioPin);
		if(ptr->mStatus & KEY_STATUS_ACTIVELOW)
		{
			j = !j;
		}
		if(j)
		{
			if(ptr->mCount < ptr->mPressPeriod)
			{
				ptr->mCount++;
			}
			if(ptr->mLongCount < ptr->mLongPressPeriod)
			{
				ptr->mLongCount++;
			}
			if((ptr->mLongCount >= ptr->mLongPressPeriod) && (ptr->mStatus & KEY_STATUS_LONGPRESSENABLE) && (!(ptr->mStatus & KEY_STATUS_LONGPRESSSTATUS_BACK)))
			{
				ptr->mStatus |= KEY_STATUS_LONGPRESSSTATUS | KEY_STATUS_LONGPRESSSTATUS_BACK;
				if(KeyEventCallBack)
				{
					KeyEventCallBack(ptr, KEY_EVENT_TYPE_LONGPRESS);
				}
			}
			if(ptr->mCount >= ptr->mPressPeriod)
			{
				if(!(ptr->mStatus & KEY_STATUS_PRESSSTATUS_BACK))
				{
					ptr->mStatus |= KEY_STATUS_PRESSSTATUS | KEY_STATUS_PRESSSTATUS_BACK;
					if(KeyEventCallBack)
					{
						KeyEventCallBack(ptr, KEY_EVENT_TYPE_PRESS);
					}
				}
				if((ptr->mStatus & KEY_STATUS_LONGPRESSENABLE) && (ptr->mLongCount < ptr->mLongPressPeriod))
				{
					
				}
				else if(ptr->mStatus & KEY_STATUS_REPEATENABLE)
				{
					ptr->mStatus &= ~KEY_STATUS_PRESSSTATUS_BACK;
					ptr->mCount = 0;
				}
			}
		}
		else
		{
			ptr->mStatus &= ~(KEY_STATUS_PRESSSTATUS_BACK | KEY_STATUS_LONGPRESSSTATUS_BACK);
			ptr->mLongCount = 0;
			ptr->mCount = 0;
		}
	}
	return(true);
}

key::key(uint8_t ucKeyIndex, gpio::GpioPortTPDF tGpioPort, uint8_t ucGpioPin, bool bActiveLow, uint32_t uiPressPeriod, bool bRepeat)
{
	KeyIndex = ucKeyIndex;
	mGpioPin.GpioPin = ucGpioPin;
	mGpioPin.GpioPort = tGpioPort;
	mStatus = bActiveLow? KEY_STATUS_ACTIVELOW: 0;
	mPressPeriod = uiPressPeriod;
	mStatus |= bRepeat? KEY_STATUS_REPEATENABLE: 0;
	mCount = 0;
	mLongCount = 0;
}

key::key(uint8_t ucKeyIndex, gpio::GpioPortTPDF tGpioPort, uint8_t ucGpioPin, bool bActiveLow, uint32_t uiPressPeriod, bool bRepeat, uint32_t uiLongPressPeriod)
{
	KeyIndex = ucKeyIndex;
	mGpioPin.GpioPin = ucGpioPin;
	mGpioPin.GpioPort = tGpioPort;
	mStatus = bActiveLow? KEY_STATUS_ACTIVELOW: 0;
	mPressPeriod = uiPressPeriod;
	mStatus |= bRepeat? KEY_STATUS_REPEATENABLE: 0;
	mStatus |= KEY_STATUS_LONGPRESSENABLE;
	mLongPressPeriod = uiLongPressPeriod;
	mCount = 0;
	mLongCount = 0;
}

key::~key()
{
	uint32_t i;
	
	for(i = 0; i < KEYBOARD_MAX_SUPPORT; i++)
	{
		if(mKey[i] == this)
		{
			mKey[i] = 0;
			break;
		}
	}
}

bool key::Pressed(void)
{
	bool ret = this->mStatus & KEY_STATUS_PRESSSTATUS;
	this->mStatus &= ~KEY_STATUS_PRESSSTATUS;
	return(ret);
}

bool key::LongPressed(void)
{
	bool ret = this->mStatus & KEY_STATUS_LONGPRESSSTATUS;
	this->mStatus &= ~KEY_STATUS_LONGPRESSSTATUS;
	return(ret);
}

bool key::Register(key *tKey)
{
	uint32_t i;
	
	if(!mKeyboardInit)
	{
		if(!commtick::RegisteTick(StatusTimerTick,1))
		{
			return(false);
		}
		mKeyboardInit = true;
	}
	for(i = 0; i < KEYBOARD_MAX_SUPPORT; i++)
	{
		if(mKey[i] == 0)
		{
			mKey[i] = tKey;
			break;
		}
	}
	if(i == KEYBOARD_MAX_SUPPORT)
	{
		return(false);
	}
	return(true);
}
